home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / tools / cie.lha / cie / etags++ / hier++.c < prev    next >
C/C++ Source or Header  |  1993-06-21  |  9KB  |  386 lines

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // hier++.c
  3. //
  4. // This program reads in C++ code and generates a "hier" file that displays the
  5. // class hierarchy.  You can then use the GNU Emacs hier-mode for traversing the
  6. // hierarchy and extracting information from your TAGS (if generated by etags++).
  7. //
  8. // Note that this program is built on the same quick-and-dirty "fuzzy" parser
  9. // that etags++ was, and will suffer the same ability to be fooled sometimes.
  10. //
  11. // Author:  Brian M. Kennedy
  12. // (C) Copyright 1993, Intellection Inc.
  13. // Permission is granted to use, copy, or modify this code as long as this author and
  14. // copyright notice is maintained in all copies.
  15. //
  16. // Note:
  17. //   This is quick, hack code that was not written to be modifiable or maintainable -- beware!!
  18. //   I would not allow code such as this into our product!  But it is okay for a quick tool hack.
  19. //   If you are a user, I hope you enjoy it.  If you are modifier, my apologies ;-(
  20.  
  21. #include "c++file.c"
  22.  
  23.  
  24. ////////////////////////////////////////////////////////////////////////////////
  25.  
  26. struct Element;
  27.  
  28. struct Element_Link
  29. {
  30.   Element*      element;
  31.   Element_Link* next;
  32.  
  33.   Element_Link (Element* element_arg, Element_Link* next_arg = 0);
  34.   
  35. };
  36.  
  37.  
  38. Element_Link::
  39. Element_Link (Element* element_arg, Element_Link* next_arg)
  40. :element(element_arg), next(next_arg)
  41. {}
  42.  
  43.   
  44. ////////////////////////////////////////////////////////////////////////////////
  45.  
  46. struct Element
  47. {
  48.   const char*    name;
  49.   Element_Link*  parents;
  50.   Element_Link*  children;
  51.  
  52.   Element (const C_File_Pos& name_pos);
  53.  
  54.   static unsigned hash (const C_File_Pos& name);
  55.   unsigned hash () const;
  56.   
  57.   Element_Link* inc_parents  (Element* parent)
  58.   { return parents  = new Element_Link(parent, parents); }
  59.   
  60.   Element_Link* inc_children (Element* child)
  61.   { return children = new Element_Link(child, children); }
  62.  
  63.   void print (ostream& os, unsigned indent) const;
  64.   
  65. };
  66.  
  67.  
  68. Element::
  69. Element (const C_File_Pos& name_pos)
  70. :name(0), parents(0), children(0)
  71. {
  72.   char* copy = new char [name_pos.length + 1];
  73.   strncpy(copy, name_pos.chars(), name_pos.length);
  74.   copy[name_pos.length] = 0;
  75.   name = copy;
  76. }
  77.  
  78.  
  79. unsigned Element::
  80. hash (const C_File_Pos& name)
  81. {
  82.   unsigned h = 0;
  83.   const char* s = name.chars();
  84.   for(unsigned i = 0; i < name.length; ++i, ++s)
  85.     h = (h << 2) + (unsigned char)(*s);
  86.   return h;
  87. }
  88.  
  89.  
  90. unsigned Element::
  91. hash () const
  92. {
  93.   unsigned h = 0;
  94.   for(const char* s = name; *s; ++s)
  95.     h = (h << 2) + (unsigned char)(*s);
  96.   return h;
  97. }
  98.  
  99.  
  100. const char blank_string [] = "                                        ";
  101.  
  102. inline const char*
  103. blanks (unsigned n)
  104.     // Returns a string of 'n' blanks
  105. {  return blank_string + sizeof(blank_string) - n - 1; }
  106.  
  107.  
  108. void Element::
  109. print (ostream& os, unsigned indent) const
  110. {
  111.   os << blanks(indent) << "* " << name << " ";
  112.   
  113.   for(Element_Link* link = parents; link; link = link->next)
  114.     os << " :" << link->element->name;
  115.   os << "\n";
  116.   
  117.   for(link = children; link; link = link->next)
  118.     link->element->print(os, indent+2);
  119. }
  120.  
  121.     
  122. ////////////////////////////////////////////////////////////////////////////////
  123.  
  124. struct Hierarchy
  125. {
  126.   unsigned       size;
  127.   Element_Link** table;
  128.  
  129.   Hierarchy (unsigned symbols);
  130.  
  131.   Element* operator () (const C_File_Pos& name) const;
  132.   
  133.   Hierarchy& inc (Element* element);
  134.   Hierarchy& inc (const C_File_Pos& name) { return inc(new Element(name)); }
  135.  
  136.   void print (ostream& os);
  137.  
  138. };
  139.  
  140.  
  141. Hierarchy::
  142. Hierarchy (unsigned symbols)
  143. :size(2*symbols + 1), table(new Element_Link* [size])
  144. {
  145.   for(unsigned i = 0; i < size; ++i)
  146.     table[i] = 0;
  147. }
  148.  
  149.  
  150. Element* Hierarchy::
  151. operator () (const C_File_Pos& name) const
  152. {
  153.   unsigned index = Element::hash(name) % size;
  154.   Element_Link* link = table[index];
  155.   while(link && ((strlen(link->element->name) != name.length)
  156.          || strncmp(link->element->name, name.chars(), name.length)))
  157.     link = link->next;
  158.   if(link)
  159.     return link->element;
  160.   else
  161.   { table[index] = new Element_Link(new Element (name), table[index]);
  162.     return table[index]->element;
  163.   }
  164. }
  165.  
  166.  
  167. Hierarchy& Hierarchy::
  168. inc (Element* element)
  169. {
  170.   unsigned index = element->hash() % size;
  171.   table[index] = new Element_Link(element, table[index]);
  172.   return *this;
  173. }
  174.  
  175.  
  176. void Hierarchy::
  177. print (ostream& os)
  178. {
  179.   for(unsigned index = 0; index < size; ++index)
  180.   { for(Element_Link* link = table[index]; link; link = link->next)
  181.     { if(!link->element->parents)
  182.     link->element->print(os, 0);
  183.     }
  184.   }
  185. }
  186.  
  187.  
  188. ////////////////////////////////////////////////////////////////////////////////
  189.  
  190. inline void
  191. parent_child (Element* parent, Element* child)
  192. {
  193.   parent->inc_children(child);
  194.   child->inc_parents(parent);
  195. }
  196.  
  197.  
  198. Boolean
  199. access_kw_p (const C_File_Pos& name)
  200. {
  201.   const char* s = name.chars();
  202.   if(*s == 'p')
  203.   {
  204.     switch(name.length)
  205.     {
  206.     case 6:  return !strncmp(s, "public",    6);
  207.     case 7:  return !strncmp(s, "private",   7) ;
  208.     case 9:  return !strncmp(s, "protected", 9);
  209.     default: return FALSE;
  210.     }
  211.   }
  212.   else if (*s == 'v')
  213.   {
  214.     switch(name.length)
  215.     {
  216.     case 7:  return !strncmp(s, "virtual",   7) ;
  217.     default: return FALSE;
  218.     }
  219.   }
  220.   else
  221.     return FALSE;
  222. }
  223.  
  224.  
  225. ////////////////////////////////////////////////////////////////////////////////
  226.  
  227. Hierarchy&
  228. get_class_hier (Hierarchy& hier, const File& file)
  229. {
  230.   C_File_Pos pos (file);
  231.   while(pos.token != END_OF_FILE)
  232.   {
  233.     switch(pos.token)
  234.     {
  235.     case CLASS_KW:
  236.     case STRUCT_KW:
  237.       pos.next_code();
  238.       if(pos.token == IDENTIFIER)
  239.       { Element* child = hier(pos);
  240.     pos.next_code();
  241.     while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
  242.     {
  243.       if(pos.token == IDENTIFIER && !access_kw_p(pos))
  244.       { Element* parent = hier(pos);
  245.         parent_child(parent, child);
  246.       }
  247.       pos.next_code();
  248.     }
  249.       }
  250.       else
  251.       { while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
  252.       pos.next_code();
  253.       }
  254.       if(pos.token == OPEN_BRACE)
  255.     pos.close_brace();
  256.       break;
  257.     case UNION_KW:
  258.     case ENUM_KW:
  259.       pos.next_code();
  260.       while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
  261.     pos.next_code();
  262.       if(pos.token == OPEN_BRACE)
  263.     pos.close_brace();
  264.       break;
  265.     case TYPEDEF_KW:        // only catches last typedef (e.g 'c' in typedef int a, b, c;)
  266.       pos.next_code();
  267.       while(pos.token != SEMI_COLON && pos.token != END_OF_FILE)
  268.     pos.next_code();
  269.       break;
  270.     case DEFINE:
  271.       pos.close_define();
  272.       break;
  273.     case OPEN_BRACE:
  274.       pos.close_brace();
  275.       break;
  276.     case OPEN_PARE:
  277.       pos.close_pare();
  278.       break;
  279.     }
  280.     pos.next_code();
  281.   }
  282.   return hier;
  283. }
  284.  
  285.  
  286. ////////////////////////////////////////////////////////////////////////////////
  287.  
  288. void
  289. usage_error (const char* progname)
  290. { cerr << "Usage " << progname;
  291.   cerr << " [-a] [-f outfile] [-s num_symbols] [-k max_infile_kbytes] infile ...";
  292.   cerr << endl;
  293.   exit(BAD);
  294. }
  295.  
  296.  
  297. main (int argc, char** argv)
  298. {
  299.   unsigned argi = 0;
  300.   char* progname = argv[argi];
  301.   
  302.   // Default flags
  303.   Boolean     append     = FALSE;
  304.   const char* outfile    = 0;
  305.   int         size       = 1024;
  306.   int         symbols    = 2000;
  307.   
  308.   // Process flags
  309.   for(argi = 1; argi < argc && argv[argi][0] == '-'; ++argi)
  310.   {
  311.     switch(argv[argi][0])
  312.     {
  313.     case '?':
  314.     case 'h':
  315.       usage_error(progname);
  316.     case 'a':
  317.       append = TRUE;
  318.       break;
  319.     case 'f':
  320.       if(outfile)
  321.       { cerr << "The -f option may only be given once." << endl;
  322.     usage_error(progname);
  323.       }
  324.       if(argv[argi][1])
  325.     outfile = &argv[argi][1];
  326.       else if(argi < argc)
  327.     outfile = argv[++argi];
  328.       else
  329.       { cerr << "The -f option must be given an argument (the outfile name)" << endl;
  330.     usage_error(progname);
  331.       }
  332.       break;
  333.     case 'k':
  334.       if(argv[argi][1])
  335.     size = atoi(&argv[argi][1]);
  336.       else if(argi < argc)
  337.     size = atoi(argv[++argi]);
  338.       else
  339.       { cerr << "The -k option must be given an argument (the max_file_size in kbytes)" << endl;
  340.     usage_error(progname);
  341.       }
  342.       break;
  343.     case 's':
  344.       if(argv[argi][1])
  345.     symbols = atoi(&argv[argi][1]);
  346.       else if(argi < argc)
  347.     symbols = atoi(argv[++argi]);
  348.       else
  349.       { cerr << "The -s option must be given an argument (the expected number of symbols)" << endl;
  350.     usage_error(progname);
  351.       }
  352.       break;
  353.     default:
  354.       ;
  355.     }
  356.   }
  357.   
  358.   // Arg value checks
  359.   if(size < 64)
  360.     size = 64;
  361.   if(symbols < 1000)
  362.     symbols = 1000;
  363.   if(!outfile)
  364.     outfile = "CLASS.hier";
  365.   
  366.   // Create File for input
  367.   File infile (size*1024);
  368.  
  369.   // Create empty hierarchy
  370.   Hierarchy hier (symbols);
  371.   
  372.   // Process files into hier
  373.   for(; argi < argc; ++argi)
  374.   {
  375.     infile.read(argv[argi]);
  376.     get_class_hier(hier, infile);
  377.   }
  378.  
  379.   // Output hierarchy
  380.   ofstream out (outfile, (append ? ios::app : ios::out));
  381.   hier.print(out);
  382.   out << flush;
  383.  
  384.   exit(GOOD);
  385. }
  386.